vulkan: Implement gsk_renderer_render_texture()
authorBenjamin Otte <otte@redhat.com>
Thu, 22 Dec 2016 18:01:07 +0000 (19:01 +0100)
committerBenjamin Otte <otte@redhat.com>
Fri, 23 Dec 2016 07:11:01 +0000 (08:11 +0100)
gsk/gskvulkanbuffer.c
gsk/gskvulkanbufferprivate.h
gsk/gskvulkancommandpool.c
gsk/gskvulkanimage.c
gsk/gskvulkanimageprivate.h
gsk/gskvulkanrender.c
gsk/gskvulkanrenderer.c
gsk/gskvulkanrenderprivate.h

index 3c1d76d37cd9857e160a3c10d1d2802b09ce7605..ec5905ba483a03c9963fb3922d400c7361d78a6b 100644 (file)
@@ -71,6 +71,12 @@ gsk_vulkan_buffer_new_staging (GdkVulkanContext  *context,
   return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
 }
 
+GskVulkanBuffer *
+gsk_vulkan_buffer_new_download (GdkVulkanContext  *context,
+                                gsize              size)
+{
+  return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+}
 void
 gsk_vulkan_buffer_free (GskVulkanBuffer *self)
 {
index 30e327e10e46eab95babbc31c822ae72c6564be5..700e40052844bc695a6ae8cbc7656f913195e7db 100644 (file)
@@ -11,6 +11,8 @@ GskVulkanBuffer *       gsk_vulkan_buffer_new                           (GdkVulk
                                                                          gsize                   size);
 GskVulkanBuffer *       gsk_vulkan_buffer_new_staging                   (GdkVulkanContext       *context,
                                                                          gsize                   size);
+GskVulkanBuffer *       gsk_vulkan_buffer_new_download                  (GdkVulkanContext       *context,
+                                                                         gsize                   size);
 void                    gsk_vulkan_buffer_free                          (GskVulkanBuffer        *buffer);
 
 VkBuffer                gsk_vulkan_buffer_get_buffer                    (GskVulkanBuffer        *self);
index 218a8c92fcff23953240cfc73556089e5ec88259..09dd333ad5f312f7f6d73316436184d7970c18fc 100644 (file)
@@ -83,10 +83,12 @@ gsk_vulkan_command_pool_submit_buffer (GskVulkanCommandPool *self,
                                1,
                                &(VkSubmitInfo) {
                                   .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+#if 0
                                   .waitSemaphoreCount = 1,
                                   .pWaitSemaphores = (VkSemaphore[1]) {
                                       gdk_vulkan_context_get_draw_semaphore (self->vulkan)
                                   },
+#endif
                                   .pWaitDstStageMask = (VkPipelineStageFlags []) {
                                       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
                                   },
@@ -94,10 +96,12 @@ gsk_vulkan_command_pool_submit_buffer (GskVulkanCommandPool *self,
                                   .pCommandBuffers = (VkCommandBuffer[1]) {
                                       command_buffer
                                   },
+#if 0
                                   .signalSemaphoreCount = 1,
                                   .pSignalSemaphores = (VkSemaphore[1]) {
                                       gdk_vulkan_context_get_draw_semaphore (self->vulkan)
                                   }
+#endif
                                },
                                fence);
 }
index b4037680b61ba5c851413f76cd0d980336b9c0be..9ef2c51bf581cfc65f74fe3d704baf0f873e6af0 100644 (file)
@@ -562,6 +562,91 @@ gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context,
   return self;
 }
 
+GskVulkanImage *
+gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
+                                      gsize             width,
+                                      gsize             height)
+{
+  GskVulkanImage *self;
+
+
+  self = gsk_vulkan_image_new (context,
+                               width,
+                               height, 
+                               VK_IMAGE_TILING_OPTIMAL,
+                               VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+                               VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+  gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_SRGB);
+
+  return self;
+}
+
+GskTexture *
+gsk_vulkan_image_download (GskVulkanImage    *self,
+                           GskVulkanUploader *uploader)
+{
+  GskVulkanBuffer *buffer;
+  GskTexture *texture;
+  guchar *mem;
+
+  gsk_vulkan_uploader_add_image_barrier (uploader,
+                                         FALSE,
+                                         &(VkImageMemoryBarrier) {
+                                             .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+                                             .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+                                             .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
+                                             .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+                                             .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                                             .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+                                             .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+                                             .image = self->vk_image,
+                                             .subresourceRange = {
+                                                 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+                                                 .baseMipLevel = 0,
+                                                 .levelCount = 1,
+                                                 .baseArrayLayer = 0,
+                                                 .layerCount = 1
+                                             }
+                                         });
+
+  buffer = gsk_vulkan_buffer_new_download (self->vulkan, self->width * self->height * 4);
+
+  vkCmdCopyImageToBuffer (gsk_vulkan_uploader_get_copy_buffer (uploader),
+                          self->vk_image,
+                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                          gsk_vulkan_buffer_get_buffer (buffer),
+                          1,
+                          (VkBufferImageCopy[1]) {
+                               {
+                                   .bufferOffset = 0,
+                                   .imageSubresource = {
+                                       .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+                                       .mipLevel = 0,
+                                       .baseArrayLayer = 0,
+                                       .layerCount = 1
+                                   },
+                                   .imageOffset = { 0, 0, 0 },
+                                   .imageExtent = {
+                                       .width = self->width,
+                                       .height = self->height,
+                                       .depth = 1
+                                   }
+                               }
+                          });
+
+  gsk_vulkan_uploader_upload (uploader);
+
+  GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan));
+
+  mem = gsk_vulkan_buffer_map (buffer);
+  texture = gsk_texture_new_for_data (mem, self->width, self->height, self->width * 4);
+  gsk_vulkan_buffer_unmap (buffer);
+  gsk_vulkan_buffer_free (buffer);
+
+  return texture;
+}
+
 void
 gsk_vulkan_image_finalize (GObject *object)
 {
index 45d8ca2e7e7e9c3d9fd7a0cda2fa212f2441f5e4..feade292e8d362ac08a6e2b8d7fe1f8e5b703a99 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <gdk/gdk.h>
 
+#include "gsk/gsktexture.h"
 #include "gsk/gskvulkancommandpoolprivate.h"
 
 G_BEGIN_DECLS
@@ -30,6 +31,12 @@ GskVulkanImage *        gsk_vulkan_image_new_from_data                  (GskVulk
                                                                          gsize                   width,
                                                                          gsize                   height,
                                                                          gsize                   stride);
+GskVulkanImage *        gsk_vulkan_image_new_for_framebuffer            (GdkVulkanContext       *context,
+                                                                         gsize                   width,
+                                                                         gsize                   height);
+
+GskTexture *            gsk_vulkan_image_download                       (GskVulkanImage         *self,
+                                                                         GskVulkanUploader      *uploader);
 
 gsize                   gsk_vulkan_image_get_width                      (GskVulkanImage         *self);
 gsize                   gsk_vulkan_image_get_height                     (GskVulkanImage         *self);
index 05ca19c6071673f0826764a5ce0f778d7df208ec..eabdd6f6ce725f0fabb9a945cd8058bd2b4b21a6 100644 (file)
@@ -24,7 +24,7 @@ struct _GskVulkanRender
 
   graphene_matrix_t mvp;
   int scale_factor;
-  VkExtent2D size;
+  VkRect2D viewport;
   VkRect2D scissor;
 
   GHashTable *framebuffers;
@@ -48,29 +48,41 @@ struct _GskVulkanRender
 };
 
 static void
-gsk_vulkan_render_compute_mvp (GskVulkanRender *self)
+gsk_vulkan_render_compute_mvp (GskVulkanRender       *self,
+                               const graphene_rect_t *rect)
 {
   GdkWindow *window = gsk_renderer_get_window (self->renderer);
   graphene_matrix_t modelview, projection;
   cairo_rectangle_int_t extents;
 
-  cairo_region_get_extents (gdk_drawing_context_get_clip (gsk_renderer_get_drawing_context (self->renderer)),
-                            &extents);
-
-  self->scale_factor = gsk_renderer_get_scale_factor (self->renderer);
-  self->size.width = gdk_window_get_width (window) * self->scale_factor;
-  self->size.height = gdk_window_get_height (window) * self->scale_factor;
-  self->scissor.offset.x = extents.x * self->scale_factor;
-  self->scissor.offset.y = extents.y * self->scale_factor;
-  self->scissor.extent.width = extents.width * self->scale_factor;
-  self->scissor.extent.height = extents.height * self->scale_factor;
+  if (rect)
+    {
+      self->scissor = (VkRect2D) { { rect->origin.x, rect->origin.y }, { rect->size.width, rect->size.height } };
+      self->viewport = self->scissor;
+      self->scale_factor = 1;
+    }
+  else
+    {
+      cairo_region_get_extents (gdk_drawing_context_get_clip (gsk_renderer_get_drawing_context (self->renderer)),
+                                &extents);
+
+      self->scale_factor = gsk_renderer_get_scale_factor (self->renderer);
+      self->viewport.offset = (VkOffset2D) { 0, 0 };
+      self->viewport.extent.width = gdk_window_get_width (window) * self->scale_factor;
+      self->viewport.extent.height = gdk_window_get_height (window) * self->scale_factor;
+      self->scissor.offset.x = extents.x * self->scale_factor;
+      self->scissor.offset.y = extents.y * self->scale_factor;
+      self->scissor.extent.width = extents.width * self->scale_factor;
+      self->scissor.extent.height = extents.height * self->scale_factor;
+    }
 
   graphene_matrix_init_scale (&modelview, self->scale_factor, self->scale_factor, 1.0);
   graphene_matrix_init_ortho (&projection,
-                              0, self->size.width,
-                              0, self->size.height,
+                              self->viewport.offset.x, self->viewport.extent.width,
+                              self->viewport.offset.y, self->viewport.extent.height,
                               ORTHO_NEAR_PLANE,
                               ORTHO_FAR_PLANE);
+
   graphene_matrix_multiply (&modelview, &projection, &self->mvp);
 }
 
@@ -450,10 +462,10 @@ gsk_vulkan_render_draw (GskVulkanRender   *self,
                     0,
                     1,
                     &(VkViewport) {
-                      .x = 0,
-                      .y = 0,
-                      .width = self->size.width,
-                      .height = self->size.height,
+                      .x = self->viewport.offset.x,
+                      .y = self->viewport.offset.x,
+                      .width = self->viewport.extent.width,
+                      .height = self->viewport.extent.height,
                       .minDepth = 0,
                       .maxDepth = 1
                     });
@@ -470,7 +482,10 @@ gsk_vulkan_render_draw (GskVulkanRender   *self,
                             .framebuffer = gsk_vulkan_render_get_framebuffer (self, self->target),
                             .renderArea = { 
                                 { 0, 0 },
-                                { self->size.width, self->size.height }
+                                {
+                                    gsk_vulkan_image_get_width (self->target),
+                                    gsk_vulkan_image_get_height (self->target)
+                                }
                             },
                             .clearValueCount = 1,
                             .pClearValues = (VkClearValue [1]) {
@@ -500,6 +515,14 @@ gsk_vulkan_render_draw (GskVulkanRender   *self,
     }
 }
 
+GskTexture *
+gsk_vulkan_render_download_target (GskVulkanRender *self)
+{
+  gsk_vulkan_uploader_reset (self->uploader);
+
+  return gsk_vulkan_image_download (self->target, self->uploader);
+}
+
 static void
 gsk_vulkan_render_cleanup (GskVulkanRender *self)
 {
@@ -589,14 +612,15 @@ gsk_vulkan_render_is_busy (GskVulkanRender *self)
 }
 
 void
-gsk_vulkan_render_reset (GskVulkanRender *self,
-                         GskVulkanImage  *target)
+gsk_vulkan_render_reset (GskVulkanRender       *self,
+                         GskVulkanImage        *target,
+                         const graphene_rect_t *rect)
 {
   gsk_vulkan_render_cleanup (self);
 
   self->target = g_object_ref (target);
 
-  gsk_vulkan_render_compute_mvp (self);
+  gsk_vulkan_render_compute_mvp (self, rect);
 }
 
 GskRenderer *
index bb3d79b48ea31ada7b10fc351f87ecd7d29f0c1a..747ed09c902a80e9a5021da123a522832e6fcbb8 100644 (file)
@@ -170,6 +170,54 @@ gsk_vulkan_renderer_unrealize (GskRenderer *renderer)
   g_clear_object (&self->vulkan);
 }
 
+static GskTexture *
+gsk_vulkan_renderer_render_texture (GskRenderer           *renderer,
+                                    GskRenderNode         *root,
+                                    const graphene_rect_t *viewport)
+{
+  GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
+  GskVulkanRender *render;
+  GskVulkanImage *image;
+  GskTexture *texture;
+#ifdef G_ENABLE_DEBUG
+  GskProfiler *profiler;
+  gint64 cpu_time;
+#endif
+
+#ifdef G_ENABLE_DEBUG
+  profiler = gsk_renderer_get_profiler (renderer);
+  gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
+#endif
+
+  render = gsk_vulkan_render_new (renderer, self->vulkan);
+
+  image = gsk_vulkan_image_new_for_framebuffer (self->vulkan,
+                                                ceil (viewport->size.width),
+                                                ceil (viewport->size.height));
+
+  gsk_vulkan_render_reset (render, image, viewport);
+
+  gsk_vulkan_render_add_node (render, root);
+
+  gsk_vulkan_render_upload (render);
+
+  gsk_vulkan_render_draw (render, self->sampler);
+
+  texture = gsk_vulkan_render_download_target (render);
+
+  g_object_unref (image);
+  gsk_vulkan_render_free (render);
+
+#ifdef G_ENABLE_DEBUG
+  cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time);
+  gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time);
+
+  gsk_profiler_push_samples (profiler);
+#endif
+
+  return texture;
+}
+
 static void
 gsk_vulkan_renderer_render (GskRenderer   *renderer,
                             GskRenderNode *root)
@@ -188,7 +236,7 @@ gsk_vulkan_renderer_render (GskRenderer   *renderer,
 
   render = self->render;
 
-  gsk_vulkan_render_reset (render, self->targets[gdk_vulkan_context_get_draw_index (self->vulkan)]);
+  gsk_vulkan_render_reset (render, self->targets[gdk_vulkan_context_get_draw_index (self->vulkan)], NULL);
 
   gsk_vulkan_render_add_node (render, root);
 
@@ -238,6 +286,7 @@ gsk_vulkan_renderer_class_init (GskVulkanRendererClass *klass)
   renderer_class->realize = gsk_vulkan_renderer_realize;
   renderer_class->unrealize = gsk_vulkan_renderer_unrealize;
   renderer_class->render = gsk_vulkan_renderer_render;
+  renderer_class->render_texture = gsk_vulkan_renderer_render_texture;
   renderer_class->begin_draw_frame = gsk_vulkan_renderer_begin_draw_frame;
 }
 
index 5696dd3001da7b5bbd5464dfaad9a5f0ec632d6b..e44f2639f26d72b723cbd56fdfc0ed43f4092828 100644 (file)
@@ -24,7 +24,8 @@ void                    gsk_vulkan_render_free                          (GskVulk
 
 gboolean                gsk_vulkan_render_is_busy                       (GskVulkanRender        *self);
 void                    gsk_vulkan_render_reset                         (GskVulkanRender        *self,
-                                                                         GskVulkanImage         *target);
+                                                                         GskVulkanImage         *target,
+                                                                         const graphene_rect_t  *rect);
 
 GskRenderer *           gsk_vulkan_render_get_renderer                  (GskVulkanRender        *self);
 
@@ -47,6 +48,8 @@ void                    gsk_vulkan_render_draw                          (GskVulk
 
 void                    gsk_vulkan_render_submit                        (GskVulkanRender        *self);
 
+GskTexture *            gsk_vulkan_render_download_target               (GskVulkanRender        *self);
+
 G_END_DECLS
 
 #endif /* __GSK_VULKAN_RENDER_PRIVATE_H__ */